const SHARED = Symbol('shared');
const WATCHER = Symbol('watcher');
const ONCEWATCHER = Symbol('oncewatcher');
const ALLWATCHER = Symbol('allwatcher');

const env = {
	develop: false,
	commonModules: new Map(),
	[SHARED]: new Map(),
	[WATCHER]: new Map(),
	[ONCEWATCHER]: new Map(),
	[ALLWATCHER]: new Set(),
	_on(prop, key, fn) {
		let fns = this[prop].get(key);
		if (fns) {
			if (!fns.includes(fn)) {
				fns.push(fn);
			}
		} else {
			this[prop].set(key, [fn]);
		}
		return this;
	},
	_off(prop, key, fn) {
		if (this[prop].has(key)) {
			let list = this[prop].get(key);
			let index = list.findIndex(a => a === fn);
			if (index !== -1) {
				list.splice(index, 1);
			}
		}
		return this;
	},
	on(key, fn) {
		return this._on(ONCEWATCHER, key, fn);
	},
	off(key, fn) {
		return this._off(WATCHER, key, fn);
	},
	once(key, fn) {
		return this._on(ONCEWATCHER, key, fn);
	},
	offonce(key, fn) {
		return this._off(ONCEWATCHER, key, fn);
	},
	onAll(fn) {
		if (this[ALLWATCHER].has(fn)) {
			this[ALLWATCHER].add(fn);
		}
		return this;
	},
	offAll() {
		this[ALLWATCHER] = new Set();
		return this;
	},
	emit(key, value) {
		(this[WATCHER].get(key) || []).forEach(a => a(value));
		(this[ONCEWATCHER].get(key) || []).forEach(a => a(value));
		this[ONCEWATCHER] = new Map();
		this[ALLWATCHER].forEach(a => a(key, value));
	},
	set(key, value) {
		this[SHARED].set(key, value);
		this.emit(key, value);
		return this;
	},
	get(key) {
		return this[SHARED].get(key);
	},
	remove(key) {
		this[SHARED].delete(key);
		this.emit(key);
		return this;
	}
};

module.exports = env;